﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace GameBoard
{
    class VisualIntersections
    {
        private List<RayHitTestResult> _findGroundLineHitResultsList;
        
        internal HitTestResultBehavior HTResult(HitTestResult rawresult)
        {
            var rayResult = rawresult as RayHitTestResult;
            if (rayResult != null)
            {
                _findGroundLineHitResultsList.Add(rayResult);
            }
            return HitTestResultBehavior.Continue;
        }


        internal class NullableHitResult
        {
            public Point3D PointHit { get; set; }

            internal NullableHitResult(RayHitTestResult rayMeshResult)
            {
                Point3D foundPoint = new Point3D(0, 0, 0);
                rayMeshResult.VisualHit.Transform.TryTransform(rayMeshResult.PointHit, out foundPoint);
                PointHit = foundPoint;
            }
        }


        public List<NullableHitResult> FindIntersections(IEnumerable<Visual3D> mapChildren, Point3D paramPoint)
        {
            _findGroundLineHitResultsList = new List<RayHitTestResult>();
            //Since we can't guarantee that the object underneath each piece is the same height (accounting for hills and terrain objects
            //We must find the location of the nearest terrain object underneath each piece
            //There will probably be more than one terrain object, as with a tower on a map, or a stacked pile of rocks
            //100000 is an arbitrarily high point -- it's likely above all other objects
            var skyPoint = new Point3D(paramPoint.X, paramPoint.Y, paramPoint.Z + 100000);
            var topDown = new Vector3D(0, 0, -1);

            foreach (var curTerrain in mapChildren)
            {
                if (curTerrain as ITerrainFeature == null
                    ||
                    !(curTerrain as ITerrainFeature).IsSolid
                    )
                {
                    continue;
                }
                VisualTreeHelper.HitTest(curTerrain, null,
                new HitTestResultCallback(HTResult),
                new RayHitTestParameters(skyPoint, topDown));
            }
            List<NullableHitResult> ret = new List<NullableHitResult>();
            //return the copy
            foreach (var cur in  _findGroundLineHitResultsList)
            {

                var res = new NullableHitResult(cur);
                if ((Math.Abs(res.PointHit.X - paramPoint.X) < .1 &&
                     Math.Abs(res.PointHit.Y - paramPoint.Y) < .1
                    ))
                {
                    ret.Add(res);
                }
            }
            return ret;
        }
    }
}
